<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  
  
  <title>IIC协议学习 | 冰泉冷涩弦凝绝，凝绝不通声暂歇</title>
  <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
  <meta name="description" content="IIC协议学习&amp;nbsp;&amp;nbsp;IIC (IIC ,Inter – Integrated Circuit )，两线式串行总线，由PHILPS公司开发用于连接微控制器的外围设备。&amp;nbsp;&amp;nbsp;由数据线SDA和时钟线SCL构成的串行总线，可发送和接收数据。在CPU与被控IC之间、IC与IC之间进行双向传送，高速IIC总线一般可达400kbps以上。IIC">
<meta property="og:type" content="article">
<meta property="og:title" content="IIC协议学习">
<meta property="og:url" content="https://gitee.com/xinhard/2023/01/28/IIC%E5%8D%8F%E8%AE%AE%E5%AD%A6%E4%B9%A0/index.html">
<meta property="og:site_name" content="冰泉冷涩弦凝绝，凝绝不通声暂歇">
<meta property="og:description" content="IIC协议学习&amp;nbsp;&amp;nbsp;IIC (IIC ,Inter – Integrated Circuit )，两线式串行总线，由PHILPS公司开发用于连接微控制器的外围设备。&amp;nbsp;&amp;nbsp;由数据线SDA和时钟线SCL构成的串行总线，可发送和接收数据。在CPU与被控IC之间、IC与IC之间进行双向传送，高速IIC总线一般可达400kbps以上。IIC">
<meta property="og:locale" content="en_US">
<meta property="og:image" content="https://img-blog.csdnimg.cn/105663c48cf54734b2a92cfa184ddb8f.png">
<meta property="og:image" content="https://img-blog.csdnimg.cn/24a289e591a04490ac121d0405767dae.png">
<meta property="og:image" content="https://img-blog.csdnimg.cn/0a1c19cca5274a14bf0c7ed13462f05d.png">
<meta property="og:image" content="https://img-blog.csdnimg.cn/ade0ace5c3eb4902ba140dae14fdc231.png">
<meta property="og:image" content="https://img-blog.csdnimg.cn/3316166dd6274a98945a7dcb05fb70a6.png">
<meta property="og:image" content="https://img-blog.csdnimg.cn/e7663ef20d3549a792d749bd8cd38250.png">
<meta property="og:image" content="https://img-blog.csdnimg.cn/d8f491fda48641a1bc0762e08b49fd38.png">
<meta property="og:image" content="https://img-blog.csdnimg.cn/68cccc2209ae43cba3ddb33cfeaf18ab.png">
<meta property="og:image" content="https://img-blog.csdnimg.cn/fe80904a870f4feb9f547b2e39c09d87.png">
<meta property="og:image" content="https://img-blog.csdnimg.cn/f684b49423fb40359cf7adc227b8cfd0.png">
<meta property="og:image" content="https://img-blog.csdnimg.cn/933b2bcb5ad64c35bcbbc6d9f0b14deb.png">
<meta property="og:image" content="https://img-blog.csdnimg.cn/6960505290534f9fb9886ca8d9c3ddf2.png">
<meta property="og:image" content="https://img-blog.csdnimg.cn/2c9d921ad4cb4589b7adf5e73a81a82e.png">
<meta property="og:image" content="https://img-blog.csdnimg.cn/8b46d6c194414493ae5efbcdb396130f.png">
<meta property="og:image" content="https://img-blog.csdnimg.cn/e2a646191a4345759338b906c9603680.png">
<meta property="og:image" content="https://img-blog.csdnimg.cn/5ca119ce67bf4d5caffc310e658094a1.png">
<meta property="og:image" content="https://img-blog.csdnimg.cn/588a984ec7c44130bfd114ebef8d431a.png">
<meta property="og:image" content="https://img-blog.csdnimg.cn/b9b4e9b762a04351a9b4ea78d0f1b9dd.png">
<meta property="og:image" content="https://img-blog.csdnimg.cn/9325219c978246bf8809550a2cb0e146.png">
<meta property="og:image" content="https://img-blog.csdnimg.cn/0af9a1bc290e4ef59154c076e3accfd4.png">
<meta property="article:published_time" content="2023-01-28T07:06:02.000Z">
<meta property="article:modified_time" content="2023-01-28T07:17:21.476Z">
<meta property="article:author" content="lxp">
<meta name="twitter:card" content="summary">
<meta name="twitter:image" content="https://img-blog.csdnimg.cn/105663c48cf54734b2a92cfa184ddb8f.png">
  
    <link rel="alternate" href="/xinhard/atom.xml" title="冰泉冷涩弦凝绝，凝绝不通声暂歇" type="application/atom+xml">
  
  
    <link rel="shortcut icon" href="/xinhard/favicon.png">
  
  
    
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/typeface-source-code-pro@0.0.71/index.min.css">

  
  
<link rel="stylesheet" href="/xinhard/css/style.css">

  
    
<link rel="stylesheet" href="/xinhard/fancybox/jquery.fancybox.min.css">

  
<meta name="generator" content="Hexo 6.3.0"></head>

<body>
  <div id="container">
    <div id="wrap">
      <header id="header">
  <div id="banner"></div>
  <div id="header-outer" class="outer">
    <div id="header-title" class="inner">
      <h1 id="logo-wrap">
        <a href="/xinhard/" id="logo">冰泉冷涩弦凝绝，凝绝不通声暂歇</a>
      </h1>
      
    </div>
    <div id="header-inner" class="inner">
      <nav id="main-nav">
        <a id="main-nav-toggle" class="nav-icon"></a>
        
          <a class="main-nav-link" href="/xinhard/">Home</a>
        
          <a class="main-nav-link" href="/xinhard/archives">Archives</a>
        
      </nav>
      <nav id="sub-nav">
        
          <a id="nav-rss-link" class="nav-icon" href="/xinhard/atom.xml" title="RSS Feed"></a>
        
        <a id="nav-search-btn" class="nav-icon" title="Search"></a>
      </nav>
      <div id="search-form-wrap">
        <form action="//google.com/search" method="get" accept-charset="UTF-8" class="search-form"><input type="search" name="q" class="search-form-input" placeholder="Search"><button type="submit" class="search-form-submit">&#xF002;</button><input type="hidden" name="sitesearch" value="https://gitee.com/xinhard"></form>
      </div>
    </div>
  </div>
</header>

      <div class="outer">
        <section id="main"><article id="post-IIC协议学习" class="h-entry article article-type-post" itemprop="blogPost" itemscope itemtype="https://schema.org/BlogPosting">
  <div class="article-meta">
    <a href="/xinhard/2023/01/28/IIC%E5%8D%8F%E8%AE%AE%E5%AD%A6%E4%B9%A0/" class="article-date">
  <time class="dt-published" datetime="2023-01-28T07:06:02.000Z" itemprop="datePublished">2023-01-28</time>
</a>
    
  </div>
  <div class="article-inner">
    
    
      <header class="article-header">
        
  
    <h1 class="p-name article-title" itemprop="headline name">
      IIC协议学习
    </h1>
  

      </header>
    
    <div class="e-content article-entry" itemprop="articleBody">
      
        <h1 id="IIC协议学习"><a href="#IIC协议学习" class="headerlink" title="IIC协议学习"></a>IIC协议学习</h1><p>&amp;nbsp;&amp;nbsp;IIC (IIC ,Inter – Integrated Circuit )，两线式串行总线，由PHILPS公司开发用于连接微控制器的外围设备。<br>&amp;nbsp;&amp;nbsp;由数据线SDA和时钟线SCL构成的串行总线，可发送和接收数据。在CPU与被控IC之间、IC与IC之间进行双向传送，高速IIC总线一般可达400kbps以上。<br>IIC是半双工通信方式。</p>
<h2 id="IIC协议描述"><a href="#IIC协议描述" class="headerlink" title="IIC协议描述"></a>IIC协议描述</h2><p>多主机IIC总线体系结构<br><img src="https://img-blog.csdnimg.cn/105663c48cf54734b2a92cfa184ddb8f.png" alt="在这里插入图片描述"></p>
<h3 id="数据的有效性"><a href="#数据的有效性" class="headerlink" title="数据的有效性"></a>数据的有效性</h3><blockquote>
<p>&amp;nbsp;&amp;nbsp;IIC 总线进行数据传送时，时钟信号为高电平期间，数据线上数据必须保持稳定，只有在时钟线上的信号为低电平期间，数据线上的高电平或低电平才允许变化。<br>总结：数据在SCL的上升沿到来之前就需要准备好，并在下降沿到来之前必须保持稳定。<br><img src="https://img-blog.csdnimg.cn/24a289e591a04490ac121d0405767dae.png" alt="在这里插入图片描述"><br>&#x3D;&#x3D;一句话&#x3D;&#x3D;概括：在SCL为高时，SDA的状态为有效</p>
</blockquote>
<h3 id="数据传输"><a href="#数据传输" class="headerlink" title="数据传输"></a>数据传输</h3><blockquote>
<p>&amp;nbsp;&amp;nbsp;一般情况下，一个标准IIC通信由4个部分组成：起始信号、从机地址传输、数据传输、停止信号。IIC通信由主机发送一个停止起始信号来启动，然后主机对从机寻址并决定数据传输方向（读or写）。IIC总线上传输数据的最小单位是1个字节（8bit），首先发送数据位为最高位，依次传输完1个字节，接收器必须发送一个应答位。每次通信的数据字节数没有限制的，全部数据传输完毕后，由主机发送停止信号，结束通信。<br><img src="https://img-blog.csdnimg.cn/0a1c19cca5274a14bf0c7ed13462f05d.png" alt="在这里插入图片描述"></p>
</blockquote>
<h3 id="IIC-总线寻址约定"><a href="#IIC-总线寻址约定" class="headerlink" title="IIC 总线寻址约定"></a>IIC 总线寻址约定</h3><blockquote>
<p>规定起始信号后的第1个字节为寻址字节，用来寻址被控器件，并规定数据的传输方向。<br>7位寻址模式：由从机7位地址(D7~D0)和一位读写为（D0）组成。<br>读写位 &#x3D; 1时，表示读，下一个字节开始主机从从机读取数据； 主机为接收器<br>读写位 &#x3D; 0时，表示写，下一个字节开始主机将数据传送给从机；主机为发送器<br>过程： 主机发送起始信号后立即传送寻址字节（广播），总线上所有器件都将寻址字节中的7位地址与自己的地址比较，if 两者相同，则该器件被认为被主机寻址，并发送应答信号<br>寻址字节中的读写位决定了主机和从机是发送器还是接收器。<br>注：不允许有两个地址相同的器件！！！ </p>
</blockquote>
<h3 id="IIC协议内容"><a href="#IIC协议内容" class="headerlink" title="IIC协议内容"></a>IIC协议内容</h3><h4 id="1-空闲状态"><a href="#1-空闲状态" class="headerlink" title="1. 空闲状态"></a>1. 空闲状态</h4><blockquote>
<p>&amp;nbsp;&amp;nbsp;IIC 总线的SDA和SCL两条信号线同时处于高电平时，规定总线为空闲状态。此时，各个器件的输出级场效应管均处于截止状态，即释放总线，由两条信号线上的各自的上拉电阻把电平拉高。</p>
</blockquote>
<h4 id="2-开始信号与停止信号"><a href="#2-开始信号与停止信号" class="headerlink" title="2. 开始信号与停止信号"></a>2. 开始信号与停止信号</h4><blockquote>
<p>&amp;nbsp;&amp;nbsp;起始信号：当SCL为高电平期间，SDA由高到低的跳变；启动信号是一种电平跳变时序信号，而不是一个电平信号。<br>停止信号： 当SCL为高期间，SDA由低电平到高电平的跳变；停止信号也是一种电平跳变的时序信号，而不是一个电平信号。<br><img src="https://img-blog.csdnimg.cn/ade0ace5c3eb4902ba140dae14fdc231.png" alt="在这里插入图片描述"></p>
</blockquote>
<h5 id="开始信号实现："><a href="#开始信号实现：" class="headerlink" title="开始信号实现："></a>开始信号实现：</h5><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * @brief: IIC 开始信号</span></span><br><span class="line"><span class="comment"> * @param: None</span></span><br><span class="line"><span class="comment"> * @return: void</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="type">void</span> <span class="title function_">IIC_Start</span><span class="params">(<span class="type">void</span>)</span></span><br><span class="line">&#123;</span><br><span class="line">    SDA_OUT();</span><br><span class="line">    SCL = <span class="number">1</span>;</span><br><span class="line">    SDA = <span class="number">1</span>;</span><br><span class="line">    delay_us(<span class="number">4</span>);</span><br><span class="line">    SDA = <span class="number">0</span>;</span><br><span class="line">    delay_us(<span class="number">4</span>);</span><br><span class="line">    <span class="comment">// 拉低SCL,准备发送或者接收数据</span></span><br><span class="line">    SCL = <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>逻辑分析仪抓取的波形：<br><img src="https://img-blog.csdnimg.cn/3316166dd6274a98945a7dcb05fb70a6.png" alt="在这里插入图片描述"></p>
<h5 id="结束信号实现："><a href="#结束信号实现：" class="headerlink" title="结束信号实现："></a>结束信号实现：</h5><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * @brief: IIC 停止信号</span></span><br><span class="line"><span class="comment"> * @param: None</span></span><br><span class="line"><span class="comment"> * @return: void</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="type">void</span> <span class="title function_">IIC_Stop</span><span class="params">(<span class="type">void</span>)</span></span><br><span class="line">&#123;</span><br><span class="line">    SDA_OUT();</span><br><span class="line">    SCL = <span class="number">0</span>;</span><br><span class="line">    SDA = <span class="number">0</span>;</span><br><span class="line">    delay_us(<span class="number">4</span>);</span><br><span class="line">    SCL = <span class="number">1</span>;</span><br><span class="line">    SDA = <span class="number">1</span>;</span><br><span class="line">    delay_us(<span class="number">4</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>逻辑分析仪抓取的波形：<br><img src="https://img-blog.csdnimg.cn/e7663ef20d3549a792d749bd8cd38250.png" alt="在这里插入图片描述"></p>
<h4 id="3-应答信号（ACK）与非应答信号（NACK）"><a href="#3-应答信号（ACK）与非应答信号（NACK）" class="headerlink" title="3. 应答信号（ACK）与非应答信号（NACK）"></a>3. 应答信号（ACK）与非应答信号（NACK）</h4><blockquote>
<p>&amp;nbsp;&amp;nbsp;IIC 总线协议规定，发送器每发送1个字节(8bit)数据，接收器必须产生1个应答信号或者非应答信号。<br>实现方法是：发送器发送完8位数据后，第9个时钟信号将数据线置高电平，接收器根据通信状态可以将数据线拉低，产生一个应答信号（表示接收器成功收到该字节），或者保持数据线为高电平，产生一个非应答信号（表示接收器接收该字节没有成功）</p>
<blockquote>
<p>注：对于反馈有效应答位的要求： 接收器在第9个时钟脉冲之前的低电平期间将SDA线拉低，并确保在该时钟的高电平期间为稳定的低电平。</p>
</blockquote>
<p><img src="https://img-blog.csdnimg.cn/d8f491fda48641a1bc0762e08b49fd38.png" alt="在这里插入图片描述"></p>
</blockquote>
<h5 id="产生应答"><a href="#产生应答" class="headerlink" title="产生应答"></a>产生应答</h5><p>SCL时钟为高时，SDA时钟为低</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * @brief: IIC 产生应答信号,sda为0</span></span><br><span class="line"><span class="comment"> * @param: None</span></span><br><span class="line"><span class="comment"> * @return: void</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="type">void</span> <span class="title function_">IIC_ACK</span><span class="params">(<span class="type">void</span>)</span></span><br><span class="line">&#123;</span><br><span class="line">    SCL = <span class="number">0</span>;</span><br><span class="line">    SDA_OUT();</span><br><span class="line">    SDA = <span class="number">0</span>;</span><br><span class="line">    delay_us(<span class="number">2</span>);</span><br><span class="line">    SCL = <span class="number">1</span>;</span><br><span class="line">    delay_us(<span class="number">2</span>);</span><br><span class="line">    SCL = <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p><img src="https://img-blog.csdnimg.cn/68cccc2209ae43cba3ddb33cfeaf18ab.png" alt="在这里插入图片描述"></p>
<h5 id="产生非应答"><a href="#产生非应答" class="headerlink" title="产生非应答"></a>产生非应答</h5><p>时钟为高时，SDA为高</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * @brief: IIC 不产生应答信号,sda为1</span></span><br><span class="line"><span class="comment"> * @param: None</span></span><br><span class="line"><span class="comment"> * @return: void</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="type">void</span> <span class="title function_">IIC_NAck</span><span class="params">(<span class="type">void</span>)</span></span><br><span class="line">&#123;</span><br><span class="line">    SCL = <span class="number">0</span>;</span><br><span class="line">    SDA_OUT();</span><br><span class="line">    SDA = <span class="number">1</span>;</span><br><span class="line">    delay_us(<span class="number">2</span>);</span><br><span class="line">    SCL = <span class="number">1</span>;</span><br><span class="line">    delay_us(<span class="number">2</span>);</span><br><span class="line">    SCL = <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p><img src="https://img-blog.csdnimg.cn/fe80904a870f4feb9f547b2e39c09d87.png" alt="在这里插入图片描述"></p>
<h5 id="等待应答"><a href="#等待应答" class="headerlink" title="等待应答"></a>等待应答</h5><p><img src="https://img-blog.csdnimg.cn/f684b49423fb40359cf7adc227b8cfd0.png" alt="在这里插入图片描述"></p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * @brief: 等待应答信号（接收）</span></span><br><span class="line"><span class="comment"> * @param: None</span></span><br><span class="line"><span class="comment"> * @return: 0: success , 1: failure</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line">u8 <span class="title function_">IIC_Wait_ACK</span><span class="params">(<span class="type">void</span>)</span></span><br><span class="line">&#123;</span><br><span class="line">    u8 err_time = <span class="number">0</span>;</span><br><span class="line">    SDA_IN();</span><br><span class="line">    SDA = <span class="number">1</span>;</span><br><span class="line">    SCL = <span class="number">1</span>;</span><br><span class="line">    delay_us(<span class="number">2</span>);</span><br><span class="line">    <span class="keyword">while</span> (Read_SDA)</span><br><span class="line">    &#123;</span><br><span class="line">        err_time++;</span><br><span class="line">        <span class="keyword">if</span> (err_time &gt; <span class="number">255</span>)</span><br><span class="line">        &#123;</span><br><span class="line">            IIC_Stop();</span><br><span class="line">            <span class="keyword">return</span> <span class="number">1</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    SCL = <span class="number">0</span>;</span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h4 id="4-发送一个字节"><a href="#4-发送一个字节" class="headerlink" title="4. 发送一个字节"></a>4. 发送一个字节</h4><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">IIC_Send(<span class="number">0xA0</span>); <span class="comment">//写</span></span><br></pre></td></tr></table></figure>

<p><img src="https://img-blog.csdnimg.cn/933b2bcb5ad64c35bcbbc6d9f0b14deb.png" alt="在这里插入图片描述"></p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * @brief: IIC 发送一个字节</span></span><br><span class="line"><span class="comment"> * @param: u8 data: 发送的数据</span></span><br><span class="line"><span class="comment"> * @param: 最后一位0:写入 1:读</span></span><br><span class="line"><span class="comment"> *            ref:  WRITE or READ</span></span><br><span class="line"><span class="comment"> * @return: void</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="type">void</span> <span class="title function_">IIC_Send</span><span class="params">(u8 data)</span></span><br><span class="line">&#123;</span><br><span class="line">    u8 i;</span><br><span class="line">    SDA_OUT();</span><br><span class="line">    SCL = <span class="number">0</span>; <span class="comment">// 拉低时钟开始传输</span></span><br><span class="line">    <span class="keyword">for</span> (i = <span class="number">0</span>; i &lt; <span class="number">8</span>; i++)</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="comment">// 从高位开始依次发送</span></span><br><span class="line">        SDA = (data &amp; <span class="number">0x80</span>) &gt;&gt; <span class="number">7</span>;</span><br><span class="line">        <span class="comment">// 移掉最高位</span></span><br><span class="line">        data = data &lt;&lt; <span class="number">1</span>;</span><br><span class="line">        delay_us(<span class="number">2</span>);</span><br><span class="line">        <span class="comment">// 以下部分为产生一个时钟周期</span></span><br><span class="line">        &#123;</span><br><span class="line">            SCL = <span class="number">1</span>;</span><br><span class="line">            delay_us(<span class="number">2</span>);</span><br><span class="line">            SCL = <span class="number">0</span>;</span><br><span class="line">            delay_us(<span class="number">2</span>);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h4 id="5-接收一个字节"><a href="#5-接收一个字节" class="headerlink" title="5. 接收一个字节"></a>5. 接收一个字节</h4><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * @brief: IIC 接收一个字节</span></span><br><span class="line"><span class="comment"> * @param: u8 ack, 1:发送应答位，0:发送nack</span></span><br><span class="line"><span class="comment"> * @return: u8 temp: 接受到的数据</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line">u8 <span class="title function_">IIC_ReceiveData</span><span class="params">(u8 ack)</span></span><br><span class="line">&#123;</span><br><span class="line">    u8 receive = <span class="number">0</span>, i;</span><br><span class="line">    SDA_IN();</span><br><span class="line">    <span class="keyword">for</span> (i = <span class="number">0</span>; i &lt; <span class="number">8</span>; i++)</span><br><span class="line">    &#123;</span><br><span class="line">        SCL = <span class="number">0</span>;</span><br><span class="line">        delay_us(<span class="number">2</span>);</span><br><span class="line">        SCL = <span class="number">1</span>;</span><br><span class="line">        delay_us(<span class="number">2</span>);</span><br><span class="line">        receive = receive &lt;&lt; <span class="number">1</span>;</span><br><span class="line">        <span class="keyword">if</span> (Read_SDA)</span><br><span class="line">            receive++;</span><br><span class="line">        delay_us(<span class="number">2</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">if</span> (ack)</span><br><span class="line">        IIC_ACK();</span><br><span class="line">    <span class="keyword">else</span></span><br><span class="line">        IIC_NAck();</span><br><span class="line">    <span class="keyword">return</span> receive;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h3 id="IIC实战"><a href="#IIC实战" class="headerlink" title="IIC实战"></a>IIC实战</h3><h4 id="AT24C02简介"><a href="#AT24C02简介" class="headerlink" title="AT24C02简介"></a>AT24C02简介</h4><blockquote>
<p>&amp;nbsp;&amp;nbsp;24C02是一个2K bit 的串行EEPROM（掉电不丢失）内部含有256个字节、在24C02里面有个一8字节的页写缓冲器。256 * 8 &#x3D; 2048&#x2F;2K bit容量，&#x3D;&#x3D;总结&#x3D;&#x3D;：每个地址8位，且每个地址能够存储1b数据，有256个地址，也就是能够存256B数据。</p>
<ol>
<li>A0，A1，A2：硬件地址引脚（可以自定义地址）</li>
<li>WP：写保护引脚，接高电平只读，接地允许读和写</li>
<li>SCL和SDA：IIC总线<blockquote>
<p>SCL串行时钟：AT24C02串行时钟输入管脚用于产生器件所有数据发送或者接收时钟，这是个输入管脚。<br>SDA双向串行数据&#x2F;地址管脚，用于器件所有数据的发送或者接收，SDA是一个&#x3D;&#x3D;开漏输出&#x3D;&#x3D;管脚，可与其它开漏输出或者&#x3D;&#x3D;集电极开漏输出&#x3D;&#x3D;进行<strong>线或（wire-OR）</strong></p>
</blockquote>
</li>
<li>高位固定0xA0，可编程3位，最后一位读写位（&#x3D;&#x3D;高（1）为读，低（0）为写&#x3D;&#x3D;）<blockquote>
<p><img src="https://img-blog.csdnimg.cn/6960505290534f9fb9886ca8d9c3ddf2.png" alt="在这里插入图片描述"><br><img src="https://img-blog.csdnimg.cn/2c9d921ad4cb4589b7adf5e73a81a82e.png" alt="在这里插入图片描述"></p>
</blockquote>
</li>
</ol>
</blockquote>
<h5 id="写数据时序"><a href="#写数据时序" class="headerlink" title="写数据时序"></a>写数据时序</h5><blockquote>
<p>先看时序图：</p>
<blockquote>
<p><img src="https://img-blog.csdnimg.cn/8b46d6c194414493ae5efbcdb396130f.png" alt="在这里插入图片描述"><br>操作时序： 启动总线—-发送设备地址+写—-等待应答—-发送数据存储地址（0x00 ~ 0xFF，256个字节）—- 等待应答—- 发送数据—-等待应答—-停止总线。</p>
</blockquote>
<p>&amp;nbsp;&amp;nbsp;在写数据的过程中，每成功写入一个字节，EEPROM存储空间的地址就会自动加1(相当于文件指针)，当加到0xFF后，写一个字节，地址就会溢出又变成0xFF。<br>注意：EEPROM是先写到缓冲区，然后再搬运到“掉电非易失区”。所以这个过程需要一定的时间，AT24C02这个过程不超过5ms，如果这个时候让它去响应是没有相应的！所以，我们在写入一个字节后，再写入1下一个字节前，必须等待EEPROM再次响应即可。</p>
</blockquote>
<h5 id="读数据时序"><a href="#读数据时序" class="headerlink" title="读数据时序"></a>读数据时序</h5><blockquote>
<p>读操作与写操作初始化相同，只是器件地址中的读&#x2F;写位应选择为1，有三种不同的读操作方式：</p>
<blockquote>
<p> 当前地址读 、随机读、顺序读</p>
</blockquote>
</blockquote>
<ol>
<li>当前地址读<br>&amp;nbsp;&amp;nbsp;内部地址计数器保存着上一次访问时最后一个地址加1的值，只要芯片有电，改地址就一直保存。当读到最后页的最后字节，地址会回转到0；当写到某页尾的最后一个字节，地址会回转到该页的首字节。<br><img src="https://img-blog.csdnimg.cn/e2a646191a4345759338b906c9603680.png" alt="在这里插入图片描述"></li>
<li>随机读<br>&amp;nbsp;&amp;nbsp;随机读需要先写一个目标字地址，一旦EEPROM接收器器件地址和直堤子并应答了ACK，主器件就产生一个重复的起始条件。然后，主器件发送器件地址（读写选择位为1），EEPROM应答ACK，并随时钟送出数据。主器件无需应答0，但是需发送停止条件。<br><img src="https://img-blog.csdnimg.cn/5ca119ce67bf4d5caffc310e658094a1.png" alt="在这里插入图片描述"></li>
<li>顺序读<br>&amp;nbsp;&amp;nbsp;顺序读可以通过当前地址读或随机读启动。主器件接收到一个数据后，应答ACK。只要EEPROM接收到ACK，将自动增加字地址并继续随时钟发送后面的数据。若达到存储地址末尾，地址自动回转到0，仍可继续顺序读取数据。<br>  <img src="https://img-blog.csdnimg.cn/588a984ec7c44130bfd114ebef8d431a.png" alt="在这里插入图片描述"><blockquote>
<p>具体的器件特性请参考 《24C02手册》<br><a target="_blank" rel="noopener" href="https://item.szlcsc.com/3428355.html">AT24C02手册</a></p>
</blockquote>
</li>
</ol>
<h4 id="24C02写入一个字符"><a href="#24C02写入一个字符" class="headerlink" title="24C02写入一个字符"></a>24C02写入一个字符</h4><p>逻辑分析仪抓取的波形：<br>以下波形功能：<br>在器件0xA0,的0x00地址上写入字符E的ASCII码<br><img src="https://img-blog.csdnimg.cn/b9b4e9b762a04351a9b4ea78d0f1b9dd.png" alt="在这里插入图片描述"></p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * @brief: 指定地址写入一个字节数据</span></span><br><span class="line"><span class="comment"> * @param: u8 address:</span></span><br><span class="line"><span class="comment"> * @param: u8 data</span></span><br><span class="line"><span class="comment"> * @return: None</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="type">void</span> <span class="title function_">AT24C02_WriteByAddressOfBytes</span><span class="params">(u8 address, u8 data)</span></span><br><span class="line">&#123;</span><br><span class="line">    IIC_Start();</span><br><span class="line">    <span class="comment">// 器件地址+写</span></span><br><span class="line">    IIC_Send(<span class="number">0xA0</span>);</span><br><span class="line">    IIC_Wait_ACK();</span><br><span class="line">    <span class="comment">// 发送要写入的数据地址</span></span><br><span class="line">    IIC_Send(address);</span><br><span class="line">    IIC_Wait_ACK();</span><br><span class="line">    <span class="comment">// 写入数据</span></span><br><span class="line">    IIC_Send(data);</span><br><span class="line">    IIC_ACK();</span><br><span class="line">    IIC_Stop();</span><br><span class="line">    <span class="comment">// 24c02先把数据放在缓冲区里，再写入掉电非易失区</span></span><br><span class="line">    delay_ms(<span class="number">10</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h4 id="24C02读取一个字符"><a href="#24C02读取一个字符" class="headerlink" title="24C02读取一个字符"></a>24C02读取一个字符</h4><p>  使用逻辑分析仪读取的数据：<br>  地址0x01之前写入0x88数据，现在读取0x01地址上的数据，结果为0x88，正确(✿◡‿◡)<br>  <img src="https://img-blog.csdnimg.cn/9325219c978246bf8809550a2cb0e146.png" alt="在这里插入图片描述"></p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">while</span> (<span class="number">1</span>)</span><br><span class="line">&#123;</span><br><span class="line">	key_value = KEY_Scan(<span class="number">0</span>); <span class="comment">// 按键处理程序</span></span><br><span class="line">	</span><br><span class="line">	<span class="keyword">if</span> (key_value == KEY1_PRES)<span class="comment">// 写入</span></span><br><span class="line">	&#123;</span><br><span class="line">		AT24C02_WriteByAddressOfBytes(<span class="number">1</span>,<span class="number">0x88</span>);</span><br><span class="line">		</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="keyword">else</span> <span class="keyword">if</span> (key_value == KEY0_PRES)<span class="comment">// 读取</span></span><br><span class="line">	&#123;</span><br><span class="line">		from_24c02_data = AT24C02_ReadOneByteOfAddress(<span class="number">1</span>);</span><br><span class="line">		<span class="comment">//printf(&quot;from 24c02 read data:%d\n&quot;,from_24c02_data);</span></span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>  <img src="https://img-blog.csdnimg.cn/0af9a1bc290e4ef59154c076e3accfd4.png" alt="在这里插入图片描述"></p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * @brief: 指定地址读取一个字节的数据</span></span><br><span class="line"><span class="comment"> * @param: u8 address:</span></span><br><span class="line"><span class="comment"> * @return: u8 data</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line">u8 <span class="title function_">AT24C02_ReadOneByteOfAddress</span><span class="params">(u8 address)</span></span><br><span class="line">&#123;</span><br><span class="line">    u8 temp;</span><br><span class="line">    IIC_Start();</span><br><span class="line">    <span class="comment">// 器件地址+写</span></span><br><span class="line">    IIC_Send(<span class="number">0xA0</span>);</span><br><span class="line">    IIC_Wait_ACK();</span><br><span class="line">    <span class="comment">// 数据地址</span></span><br><span class="line">    IIC_Send(address);</span><br><span class="line">    IIC_Wait_ACK();</span><br><span class="line">	IIC_Start();</span><br><span class="line">	<span class="comment">// 器件地址+读</span></span><br><span class="line">    IIC_Send(<span class="number">0xA0</span>|READ);</span><br><span class="line">    IIC_ACK();</span><br><span class="line">    <span class="comment">//接收数据，并发送非应答位</span></span><br><span class="line">    temp = IIC_ReceiveData(<span class="number">0</span>);</span><br><span class="line">    IIC_Stop();</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> temp;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * @brief: 指定地址读取length数据</span></span><br><span class="line"><span class="comment"> * @param: u8 read_start</span></span><br><span class="line"><span class="comment"> * @param: u8 length</span></span><br><span class="line"><span class="comment"> * @param: u8 *buffer</span></span><br><span class="line"><span class="comment"> * @return None</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="type">void</span> <span class="title function_">AT24C02_ReadOneBytesOfLength</span><span class="params">(u8 read_start, u8 *buffer, u8 length)</span></span><br><span class="line">&#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">while</span> (length--)</span><br><span class="line">    &#123;</span><br><span class="line">        *buffer++ = AT24C02_ReadOneByteOfAddress(read_start++);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * @brief: 指定地址写入指定长度的数据</span></span><br><span class="line"><span class="comment"> * @param: u8 start_address</span></span><br><span class="line"><span class="comment"> * @param: u8 *buffer</span></span><br><span class="line"><span class="comment"> * @param: u8 length</span></span><br><span class="line"><span class="comment"> * @return: None</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="type">void</span> <span class="title function_">AT24C02_WriteByAddressOfLengthData</span><span class="params">(u8 start_address, u8 *buffer, u8 length)</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="keyword">while</span> (length--)</span><br><span class="line">    &#123;</span><br><span class="line">        AT24C02_WriteByAddressOfBytes(start_address++, *buffer);</span><br><span class="line">        buffer++;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>&#x3D;&#x3D;总结&#x3D;&#x3D;：</p>
<blockquote>
<p>IIC功能非常强大，这里使用软件IIC是为了方便移植程序。我们在使用中只需用关注具体器件IIC的时序即可，写好时序，通过逻辑分析仪去Debug分析程序代码，进而实现功能。</p>
</blockquote>

      
    </div>
    <footer class="article-footer">
      <a data-url="https://gitee.com/xinhard/2023/01/28/IIC%E5%8D%8F%E8%AE%AE%E5%AD%A6%E4%B9%A0/" data-id="clhnlozw400017ku8e7hidlz8" data-title="IIC协议学习" class="article-share-link">Share</a>
      
      
      
    </footer>
  </div>
  
    
<nav id="article-nav">
  
    <a href="/xinhard/2023/05/14/STM32%E5%8F%AF%E8%B0%83%E7%94%B5%E6%BA%90/" id="article-nav-newer" class="article-nav-link-wrap">
      <strong class="article-nav-caption">Newer</strong>
      <div class="article-nav-title">
        
          STM32可调电源
        
      </div>
    </a>
  
  
    <a href="/xinhard/2022/09/25/%E7%89%A9%E8%81%94%E7%BD%91%E6%AF%95%E8%AE%BE-%E6%99%BA%E8%83%BD%E9%B1%BC%E7%BC%B8/" id="article-nav-older" class="article-nav-link-wrap">
      <strong class="article-nav-caption">Older</strong>
      <div class="article-nav-title">物联网毕设-智能鱼缸</div>
    </a>
  
</nav>

  
</article>


</section>
        
          <aside id="sidebar">
  
    

  
    

  
    
  
    
  <div class="widget-wrap">
    <h3 class="widget-title">Archives</h3>
    <div class="widget">
      <ul class="archive-list"><li class="archive-list-item"><a class="archive-list-link" href="/xinhard/archives/2023/05/">May 2023</a></li><li class="archive-list-item"><a class="archive-list-link" href="/xinhard/archives/2023/01/">January 2023</a></li><li class="archive-list-item"><a class="archive-list-link" href="/xinhard/archives/2022/09/">September 2022</a></li></ul>
    </div>
  </div>


  
    
  <div class="widget-wrap">
    <h3 class="widget-title">Recent Posts</h3>
    <div class="widget">
      <ul>
        
          <li>
            <a href="/xinhard/2023/05/14/STM32%E5%8F%AF%E8%B0%83%E7%94%B5%E6%BA%90/">STM32可调电源</a>
          </li>
        
          <li>
            <a href="/xinhard/2023/01/28/IIC%E5%8D%8F%E8%AE%AE%E5%AD%A6%E4%B9%A0/">IIC协议学习</a>
          </li>
        
          <li>
            <a href="/xinhard/2022/09/25/%E7%89%A9%E8%81%94%E7%BD%91%E6%AF%95%E8%AE%BE-%E6%99%BA%E8%83%BD%E9%B1%BC%E7%BC%B8/">物联网毕设-智能鱼缸</a>
          </li>
        
          <li>
            <a href="/xinhard/2022/09/25/%E7%A1%AC%E4%BB%B6%E9%A1%B9%E7%9B%AE%E6%B1%87%E6%80%BB/">硬件项目汇总</a>
          </li>
        
      </ul>
    </div>
  </div>

  
</aside>
        
      </div>
      <footer id="footer">
  
  <div class="outer">
    <div id="footer-info" class="inner">
      
      &copy; 2023 lxp<br>
      Powered by <a href="https://hexo.io/" target="_blank">Hexo</a>
    </div>
  </div>
</footer>

    </div>
    <nav id="mobile-nav">
  
    <a href="/xinhard/" class="mobile-nav-link">Home</a>
  
    <a href="/xinhard/archives" class="mobile-nav-link">Archives</a>
  
</nav>
    


<script src="/xinhard/js/jquery-3.4.1.min.js"></script>



  
<script src="/xinhard/fancybox/jquery.fancybox.min.js"></script>




<script src="/xinhard/js/script.js"></script>





  </div>
</body>
</html>